#!/usr/bin/env python2

import commands
import fcntl
import os
import re
import sys
import string
import struct
import socket
import time
import thread
import errno
from threading import Thread
from config import Config
from utils import Exp, _dmsg, _dwarn, _derror, _get_value, _ntoa, _aton, _net_mask, _get_network

NUM = 0
numlock = thread.allocate_lock()
config = Config()
home = os.path.abspath(config.home)
logfile = ""

def get_nic_ip(ifname):
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    localIP = socket.inet_ntoa(fcntl.ioctl(s.fileno(), 0x8915, struct.pack('256s' , ifname[:15]))[20:24])
    return localIP


def localnic1():
    confignet = config.network()
    localnet = _get_network()

    # print("%s %s %s" % (dip, network, denmask))
    # print(ip)
    # print(confignet)
    # print(localnet)

    localmap = []
    s = socket.gethostbyname_ex(config.hostname)
    for i in s[2]:
        localmap.append(i)

    net = []
    for i in confignet:
        net.append(_aton(i[0]) & _aton(i[1]))

    localnic = []
    for (k, v) in localnet.items():
        n = _aton(v[0]) & _aton(v[1])
        if n in net and v[0] in localmap:
            localnic.append(k)

    if (len(localnic) == 0):
        localnic.append("nodev")

    return localnic

def localnic(dip, network, denmask):
    cmd = "netstat -nr |grep " + "'" + network + " '" + " |awk '{print $NF}'"
    (status, output) = commands.getstatusoutput(cmd)
    if (output != ''):
        nic = output
        return nic
    else:
        _derror("%s %s %s" % (dip, network, denmask))
        return "nodev"

class testping(Thread):
   def __init__ (self, ip):
      Thread.__init__(self)
      self.ip = ip
      self.status = -1

   def run(self):
        global NUM

        cmd = 'ping -c 2 -i 0.1 -w 2 ' + self.ip
        (status, output) = commands.getstatusoutput(cmd)
        if status == 0:
                numlock.acquire()
                NUM += 1
                numlock.release()

class arping(Thread):
    def __init__ (self, ip, total):
        Thread.__init__(self)
        self.ip = ip
        self.total = total
        self.deadline = '10'

    def run(self):
        global NUM
        global LOCAL_NIC
        global LOCAL_IP

        if self.ip == LOCAL_IP:
            log_append('=> %s ok' % (self.ip))
            numlock.acquire()
            NUM += 1
            numlock.release()
        else:
            cmd = 'ping -c 2 -i 0.1 -w 2 ' + self.ip + ' > /dev/null'
            os.system(cmd)
            cmd = 'arping -c 10 ' + self.ip + ' -f ' + ' -I ' + LOCAL_NIC + ' -w ' + self.deadline
            (status, output) = commands.getstatusoutput(cmd)
            if status == 0:
                log_append('=> %s ok' % (self.ip))
                numlock.acquire()
                NUM += 1
                numlock.release()
            else:
                log_append('!! %s failed' % (cmd))

class multi_arping(Thread):
    def __init__ (self, iplist, total):
        Thread.__init__(self)
        self.iplist = iplist
        self.total = total
        self.deadline = '5'

    def run(self):
        global NUM
        global NETLIST

	cmd = """ifconfig  | grep "inet " |awk '{print $2}' |awk -F':'  '{print $2}'"""
	(status, output) = commands.getstatusoutput(cmd)
        if (output == '\n'):
            cmd = """ifconfig  | grep "inet " |awk '{print $2}' |awk -F':'  '{print $1}'"""
            (status, output) = commands.getstatusoutput(cmd)
	localaddrs = output.split()
	ret = 1
	for ip in self.iplist:
            if ip in localaddrs:  # local ip list
                log_append('=> %s ok' % (ip))
                numlock.acquire()
                NUM += 1
                numlock.release()
		break
            else:
		for i in range(len(NETLIST)):
                    nic = localnic1()[0]
                    if (nic == 'nodev'):
                        log_append('!! %s failed' % (cmd))
                    elif (nic == 'lo'):
                        log_append('=> %s ok' % (ip))
                        numlock.acquire()
                        NUM += 1
                        numlock.release()
                        ret = 0
                        break
                    cmd = 'ping -c 2 -i 0.1 -w 2 ' + ip + ' > /dev/null'
                    os.system(cmd)
               	    cmd = 'arping -c 10 ' + ip + ' -f' + ' -I ' + nic + ' -w ' + self.deadline
                    (status, output) = commands.getstatusoutput(cmd)
                    if status == 0:
                        log_append('=> %s ok' % (ip))
                        numlock.acquire()
                        NUM += 1
                        numlock.release()
                        ret = 0
		        break
                    else:
                        log_append('!! %s failed' % (cmd))
		if ret == 0:
                    break

def log_append(message):
    if (logfile == ''):
        print '[%s %s] %s' % (time.time(), time.strftime('%F %T'), message)
    else:
        f = file(logfile, 'a')
        f.write('[%s %s] %s\n' % (time.time(), time.strftime('%F %T'), message))
        f.close()

if __name__ == '__main__':
    if (len(sys.argv) != 1):
        if (sys.argv[1] == '--log'):
            logdir = home + "/log"
            os.system("mkdir -p %s" % (logdir))
            logfile = '%s/fence.log' % (logdir)
        else:
            print("invalid argument")
            sys.exit(errno.EINVAL)

    NETLIST = config.network()
    iplist = []
    for n in NETLIST:
        for (k, v) in config.hosts.items():
            s = socket.gethostbyname_ex(k)
            for i in s[2]:
                if (_net_mask(i, n[1]) == n[0]):
                    iplist.append(i)

    limit = len(iplist) / 2 + 1
    log_append('==> %s, limit %d' % (iplist, limit))

    pinglist = []
    for ips in iplist:
        try:
            current = multi_arping([ips], len(iplist))
            pinglist.append(current)
            current.start()
        except Exp, e:
            log_append(e.err)
            sys.exit(e.errno)

    for pingle in pinglist:
        pingle.join()

    log_append('<== passed/total: %d/%d' % (NUM, len(iplist)))
    if NUM >= limit or limit == 1:
        # print ("%d %d" % (NUM, limit))
        sys.exit (0)
    else:
        sys.exit(errno.ENONET)
